home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / MacPerl ƒ / Perl Source ƒ / MacPerl / MPFile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-15  |  16.1 KB  |  764 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Real Perl Application
  3. File        :    MPFile.c            -
  4. Author    :    Matthias Neeracher
  5.  
  6. A lot of this code is borrowed from 7Edit written by
  7. Apple Developer Support UK
  8.  
  9. Started    :    17Mar93                                Language    :    MPW C
  10. Modified    :    29May93    MN    Compiles correctly
  11.                 30May93    MN    Support Console Windows
  12.                 13Aug93    MN    Write bounds rectangles
  13.                 17Aug93    MN    Enable Save
  14.                 28Aug93    MN    Handle multiple preference files
  15.                 17Sep93    MN    Runtime version
  16. Last        :    17Sep93
  17. *********************************************************************/
  18.  
  19. #include <Errors.h>
  20. #include <Resources.h>
  21. #include <Desk.h>
  22. #include <PLStringFuncs.h>
  23. #include <AppleEvents.h>
  24. #include <AERegistry.h>
  25. #include <StandardFile.h>
  26. #include <TFileSpec.h>
  27.  
  28. #include "MPFile.h"
  29. #include "MPSave.h"
  30.  
  31. /**-----------------------------------------------------------------------
  32.         Name:             FileError
  33.         Purpose:        Puts up an error alert.
  34.     -----------------------------------------------------------------------**/
  35.  
  36.  
  37. #pragma segment File
  38.  
  39. pascal void FileError(Str255 s, Str255 f)
  40. {
  41.     short    alertResult;
  42.  
  43.     SetCursor(&qd.arrow);
  44.     ParamText(s, f, "", "");
  45.      alertResult = Alert(ErrorAlert, nil);
  46. }
  47.  
  48. /**-----------------------------------------------------------------------
  49.         Name:             DoClose
  50.         Purpose:        Closes a window.
  51.     -----------------------------------------------------------------------**/
  52.  
  53. #pragma segment File
  54.  
  55. pascal OSErr DoClose(WindowPtr aWindow, Boolean canInteract, DescType dialogAnswer)
  56. {
  57.      DPtr    aDocument;
  58.      short   alertResult;
  59.      Str255  theName;
  60.     OSErr   myErr;
  61.  
  62.     myErr = noErr;
  63.  
  64.      if (gWCount > 0) {
  65.         aDocument = DPtrFromWindowPtr(aWindow);
  66.  
  67.         if (aDocument->kind == kDocumentWindow) {
  68.             if (aDocument->dirty)
  69.                 if (canInteract && (dialogAnswer==kAEAsk)) {
  70.                     if (aDocument->u.reg.everSaved == false)
  71.                         GetWTitle(aWindow, theName); /* Pick it up as a script may have changed it */
  72.                     else
  73.                         PLstrcpy(theName, aDocument->theFileName);
  74.     
  75.                     ParamText(theName, "", "", "");
  76.                     SetCursor(&qd.arrow);
  77.                     alertResult = Alert(SaveAlert, nil);
  78.                     switch (alertResult) {
  79.                     case aaSave:
  80.                         myErr = SaveAskingName(aDocument, canInteract);
  81.                         break;
  82.     
  83.                     case aaCancel:
  84.                         return userCanceledErr;
  85.     
  86.                     case aaDiscard:
  87.                         aDocument->dirty = false;
  88.                         break;
  89.                     }
  90.                 } else {
  91.                     if (dialogAnswer==kAEYes)
  92.                         myErr = SaveAskingName(aDocument, canInteract);
  93.                     else
  94.                         myErr = noErr; /* Don't save */
  95.                 }
  96.                 
  97.             if (!myErr) {
  98. #ifndef RUNTIME
  99.                 if (aDocument->kind == kDocumentWindow && aDocument->u.reg.numSections)
  100.                     DeRegisterAllSections(aDocument);
  101. #endif
  102.  
  103.                 CloseMyWindow(aWindow);
  104.             }
  105.         } else if (aDocument->u.cons.selected) {
  106.             if (!gQuitting) {
  107.                 SysBeep(0);
  108.     
  109.                 return userCanceledErr;
  110.             }
  111.         } else 
  112.             SaveConsole(aDocument);
  113.     } else
  114.         myErr = errAEIllegalIndex;
  115.  
  116.     return myErr;
  117. }
  118.  
  119. #pragma segment File
  120.  
  121. //  DoQuit
  122. //  saveOpt - one of kAEAsk,kAEYes,kAENo
  123. //  if kAEYes or kAEAsk then AEInteactWithUser should have been called
  124. //  before DoQuit. Assumes that it can interact if it needs to.
  125.  
  126. pascal void DoQuit(DescType saveOpt)
  127. {
  128.     WindowPeek    aWindow;
  129.     WindowPeek    nextWindow;
  130.     short            theKind;
  131.  
  132.     if (gRunningPerl && (Alert(AbortAlert, nil) == 2))
  133.         return;
  134.         
  135.     gQuitting = true;
  136.  
  137.     for (aWindow = (WindowPeek) FrontWindow(); aWindow; aWindow = nextWindow) {
  138.         nextWindow = aWindow->nextWindow;
  139.         if (Ours((WindowPtr) aWindow)) {
  140.             if (DoClose((WindowPtr) aWindow, true, saveOpt)) {
  141.                 gQuitting = false;
  142.                 
  143.                 return;
  144.             }
  145.         } else {
  146.             theKind = aWindow->windowKind;
  147.             if (theKind < 0)
  148.                 CloseDeskAcc(theKind);
  149.         }
  150.     }
  151. }
  152.  
  153. pascal Boolean GetFileFilter(ParmBlkPtr info)
  154. {
  155.     switch (info->fileParam.ioFlFndrInfo.fdType) {
  156.     case 'APPL':
  157.         switch (info->fileParam.ioFlFndrInfo.fdCreator) {
  158.         case MPRtSig:
  159.             return false;
  160.         case MPAppSig:
  161.             return !info->fileParam.ioFlLgLen;
  162.         default:
  163.             return true;
  164.         }
  165.     case 'TEXT':
  166.         return false;
  167.     default:
  168.         return true;
  169.     }
  170. }
  171.  
  172. pascal OSErr GetFile(FSSpec *theFSSpec)
  173. {
  174. #ifndef RUNTIME
  175.  
  176.     SFTypeList         myTypes = {'TEXT', 'APPL'};
  177.     StandardFileReply  reply;
  178.  
  179.     StandardGetFile(GetFileFilter, 2, myTypes, &reply);
  180.  
  181.     if (reply.sfGood) {
  182.         *theFSSpec = reply.sfFile;
  183.         return noErr;
  184.     } else
  185.         return userCanceledErr;
  186.         
  187. #else
  188.  
  189.     SFTypeList     myTypes = {'TEXT', 'APPL'};
  190.     SFReply          reply;
  191.     Point            where;
  192.  
  193.     where.h = where.v = 75;
  194.  
  195.     SFGetFile(
  196.         where, "\p", 
  197.         GetFileFilter, 2, myTypes, 
  198.         (DlgHookProcPtr) nil,
  199.         &reply);
  200.  
  201.     if (reply.good)
  202.         return WD2FSSpec(reply.vRefNum, reply.fName, theFSSpec);
  203.     else
  204.         return userCanceledErr;
  205.         
  206. #endif
  207. }
  208.  
  209. #pragma segment File
  210.  
  211. pascal OSErr DoCreate(FSSpec theSpec)
  212. {
  213.     OSErr err;
  214.  
  215. #ifndef RUNTIME
  216.     err = FSpCreate(&theSpec, MPAppSig, 'TEXT', smSystemScript);
  217. #else
  218.     err = HCreate(theSpec.vRefNum, theSpec.parID, theSpec.name, MPAppSig, 'TEXT');
  219. #endif
  220.  
  221.     if (!err)
  222.         HCreateResFile(theSpec.vRefNum, theSpec.parID, theSpec.name);
  223.     else
  224.         ShowError("\pCreating", err);
  225.  
  226.     return err;
  227. }
  228.  
  229. pascal OSErr SaveConsole(DPtr doc)
  230. {
  231.     OSErr            err;
  232.     short       resFile;
  233.     HHandle     theHHandle;
  234.     Str255        title;
  235.     Boolean        existing;
  236.     
  237.     if (gPrefsFile) {
  238.         resFile    =    CurResFile();
  239.         UseResFile(gPrefsFile);
  240.         GetWTitle(doc->theWindow, title);
  241.         
  242.         if (theHHandle = (HHandle) Get1NamedResource('TFSS', title)) {
  243.             existing = true;
  244.         } else {
  245.             existing = false;
  246.             theHHandle = (HHandle)NewHandle(sizeof(HeaderRec));
  247.         }
  248.         
  249.         HLock((Handle)theHHandle);
  250.     
  251.         (*theHHandle)->theRect     = doc->theWindow->portRect;
  252.         OffsetRect(
  253.             &(*theHHandle)->theRect,
  254.             -doc->theWindow->portBits.bounds.left,
  255.             -doc->theWindow->portBits.bounds.top);
  256.             
  257.         GetFontName((*(doc->theText))->txFont, &(*theHHandle)->theFont);
  258.         
  259.         (*theHHandle)->theSize     = (*(doc->theText))->txSize;
  260.         (*theHHandle)->lastID      = 0;
  261.         (*theHHandle)->numSections = 0;
  262.     
  263.         HUnlock((Handle)theHHandle);
  264.     
  265.         if (existing) {
  266.             ChangedResource((Handle) theHHandle);
  267.             WriteResource((Handle) theHHandle);
  268.             UpdateResFile(gPrefsFile);
  269.         } else {
  270.             AddResource((Handle)theHHandle, 'TFSS', Unique1ID('TFSS'), title);
  271.         }
  272.         
  273.         err = ResError();
  274.         
  275.         UseResFile(resFile);
  276.     }
  277.     
  278.     DoHideWindow(doc->theWindow);
  279.     TESetSelect(0, 32767, doc->theText);
  280.     TEDelete(doc->theText);
  281.     
  282.     if (doc->u.cons.fence < 32767)
  283.         doc->u.cons.fence    = 0;
  284.     
  285.     return err;
  286.  
  287. pascal void ApplySettings(DPtr doc, HPtr settings)
  288. {
  289.     short        fNum;
  290.     FontInfo    info;
  291.     Rect        bounds;
  292.     
  293.     GetFNum(settings->theFont, &fNum);
  294.     SetPort(doc->theWindow);
  295.     TextFont(fNum);
  296.     TextSize(settings->theSize);
  297.     GetFontInfo(&info);
  298.     
  299.     (*doc->theText)->txFont         = fNum;
  300.     (*doc->theText)->txSize         = settings->theSize;
  301.     (*doc->theText)->lineHeight    = info.ascent+info.descent+info.leading;
  302.     (*doc->theText)->fontAscent    = info.ascent;
  303.     
  304.     bounds                                = settings->theRect;
  305.     InsetRect(&bounds, 20, 20);
  306.     
  307.     if (settings->theRect.right > settings->theRect.left + 50 &&
  308.         settings->theRect.bottom > settings->theRect.top  + 50 &&
  309.         RectInRgn(&bounds, GetGrayRgn())
  310.     ) {
  311.         MoveWindow(doc->theWindow, settings->theRect.left, settings->theRect.top, false);
  312.         SizeWindow(
  313.             doc->theWindow,
  314.             settings->theRect.right - settings->theRect.left,
  315.             settings->theRect.bottom - settings->theRect.top,
  316.             false);
  317.     }
  318.         
  319.     ResizeWindow(doc);
  320. }
  321.  
  322. pascal void RestoreConsole(DPtr doc)
  323. {
  324.     short       resFile;
  325.     HHandle     theHHandle;
  326.     Str255        title;
  327.     
  328.     if (!gPrefsFile)
  329.         return;
  330.         
  331.     resFile    =    CurResFile();
  332.     UseResFile(gPrefsFile);
  333.     GetWTitle(doc->theWindow, title);
  334.     
  335.     if (theHHandle = (HHandle) Get1NamedResource('TFSS', title)) {
  336.          HLock((Handle)theHHandle);
  337.         
  338.         ApplySettings(doc, *theHHandle);
  339.         
  340.         HUnlock((Handle)theHHandle);
  341.     }
  342.     
  343.     UseResFile(resFile);
  344. }
  345.  
  346.  
  347. /** -----------------------------------------------------------------------
  348.         Name:         GetFileContents
  349.         Purpose:        Opens the document specified by theFSSpec and puts
  350.                         the contents into theDocument.
  351.      -----------------------------------------------------------------------**/
  352.  
  353. #pragma segment File
  354.  
  355. pascal OSErr GetFileContents(FSSpec spec, DPtr theDocument)
  356. {
  357.     long            theSize;
  358.     short            oldRes;
  359.     short            resFile;
  360.     short            refNum;
  361.     OSErr            err;
  362.     HHandle        aHandle;
  363.     Handle        gHandle;
  364.  
  365.     oldRes    =    CurResFile();
  366.     resFile     =    HOpenResFile(spec.vRefNum, spec.parID, spec.name, fsRdPerm);
  367.  
  368.     switch (theDocument->type) {
  369.     case kOldRuntime6Doc:
  370.     case kPlainTextDoc:
  371. #ifndef RUNTIME
  372.         if (err = HOpenDF(spec.vRefNum, spec.parID, spec.name, fsRdPerm, &refNum)) {
  373.             ShowError("\pread file - HOpenDF", err);
  374. #else
  375.         if (err = HOpen(spec.vRefNum, spec.parID, spec.name, fsRdPerm, &refNum)) {
  376.             ShowError("\pread file - HOpen", err);
  377. #endif
  378.             refNum = 0;
  379.             
  380.             goto giveUp;
  381.         }
  382.     
  383.         if (err = GetEOF(refNum, &theSize))
  384.             goto giveUp;
  385.  
  386.           gHandle = NewHandle(theSize);
  387.  
  388.         HLock(gHandle);
  389.         if (err = FSRead(refNum, &theSize, *gHandle))
  390.             return err;
  391.         HUnlock(gHandle);
  392.         FSClose(refNum);
  393.         break;
  394.         
  395. giveUp:    
  396.         if (refNum)
  397.             FSClose(refNum);
  398.             
  399.         if (resFile > -1)
  400.             CloseResFile(resFile);
  401.         
  402.         UseResFile(oldRes);
  403.         
  404.         return err;
  405.     default:
  406.         gHandle    =    Get1NamedResource('TEXT', "\p!");
  407.         
  408.         if (gHandle) 
  409.             DetachResource(gHandle);
  410.         else {
  411.             err = ResError();
  412.             
  413.             goto giveUp;
  414.         }
  415.         break;
  416.     }
  417.  
  418.     theDocument->u.reg.numSections = 0;
  419.  
  420.     if (resFile != -1) {
  421.         aHandle = nil;
  422.  
  423.         if (Count1Resources('TFSS'))
  424.             aHandle = (HHandle)Get1Resource('TFSS', 255);
  425.  
  426.         if (aHandle) {
  427.             theDocument->u.reg.numSections = (*aHandle)->numSections;
  428.             
  429.             HLock((Handle) aHandle);
  430.             ApplySettings(theDocument, *aHandle);
  431.         }
  432.  
  433.         /*
  434.             If there is a print record saved, ditch the old one
  435.             created by new document and fill this one in
  436.         */
  437.         if (Count1Resources('TFSP')) {
  438.             if (theDocument->thePrintSetup)
  439.                 DisposHandle((Handle)theDocument->thePrintSetup);
  440.  
  441.             theDocument->thePrintSetup = (THPrint)Get1Resource('TFSP', 255);
  442.               HandToHand((Handle *)&theDocument->thePrintSetup);
  443.  
  444.             PrValidate(theDocument->thePrintSetup);
  445.         }
  446.  
  447. #ifndef RUNTIME
  448.         if (theDocument->u.reg.numSections) {
  449.             ReadSectionRecords(theDocument);
  450.             ReadAllSectionResources(theDocument);
  451.         }
  452. #else
  453.         theDocument->u.reg.numSections    =    0;
  454. #endif
  455.  
  456.         CloseResFile(resFile);
  457.  
  458.         if (err = ResError()) {
  459.             ShowError("\pread file- CloseResFile", err);
  460.             return err;
  461.         }
  462.     }
  463.  
  464.     HLock(gHandle);
  465.     if (GetHandleSize(gHandle) > 32000) {
  466.         PtrToXHand(
  467.             *gHandle, 
  468.             (*theDocument->theText)->hText, 
  469.             GetHandleSize(gHandle));
  470.         
  471.         err = elvisErr;
  472.     } else
  473.         TESetText(*gHandle, GetHandleSize(gHandle), theDocument->theText);
  474.     DisposHandle(gHandle);
  475.  
  476.     if (err == fnfErr)
  477.         return noErr;
  478.     else
  479.           return err;
  480. } /* GetFileContents */
  481.  
  482.  
  483. #pragma segment File
  484.  
  485. pascal OSErr SaveAskingName(DPtr aDocument, Boolean canInteract)
  486. {
  487.     OSErr    myErr;
  488.  
  489.     if (aDocument->kind != kDocumentWindow || !aDocument->u.reg.everSaved) {
  490.  
  491.         if (canInteract) {
  492.             if (myErr = GetFileNameToSaveAs(aDocument))
  493.                 return myErr;
  494.  
  495.             if (myErr = DoSave(aDocument, aDocument->theFSSpec))
  496.                 return myErr;
  497.  
  498. #ifndef RUNTIME
  499.             AssocAllSections(aDocument);
  500. #endif
  501.  
  502.             return noErr;
  503.         } else
  504.             return errAENoUserInteraction;
  505.  
  506.     } else
  507.         return SaveUsingTemp(aDocument);
  508. }
  509.  
  510. #pragma segment File
  511.  
  512. pascal OSErr SaveUsingTemp(DPtr theDocument)
  513. {
  514.     Str255    tempName;
  515.     OSErr        err;
  516.     FSSpec    tempFSSpec;
  517.  
  518.     /*save the file to disk using a temporary file*/
  519.     /*this is the recommended way of doing things*/
  520.     /*first write out the file to disk using a temporary filename*/
  521.     /*if it is sucessfully written, exchange the temporary file with the last one saved*/
  522.     /*then delete the temporary file- so if anything goes wrong, the original version is still there*/
  523.     /*first generate the temporary filename*/
  524.  
  525.     GetTempFileName(theDocument, &tempName);
  526.     /*create this file on disk*/
  527.  
  528.     tempFSSpec = theDocument->theFSSpec;
  529.     PLstrcpy(tempFSSpec.name, tempName);
  530.  
  531.     if (err = DoCreate(tempFSSpec))
  532.         return err;
  533.  
  534.     if (err = DoSave(theDocument, tempFSSpec))
  535.         return err;
  536.     
  537. #ifndef RUNTIME
  538.     if (err = FSpExchangeFiles(&tempFSSpec, &theDocument->theFSSpec))
  539.         return err;
  540.  
  541.     /*we've exchanged the files, now delete the temporary one*/
  542.  
  543.     err = FSpDelete(&tempFSSpec);
  544. #else
  545.     err = FSpSmartMove(&tempFSSpec, &theDocument->theFSSpec);
  546. #endif
  547.     
  548.     if (!err)
  549.         theDocument->dirty = false;
  550.  
  551.     return err;
  552. }
  553.  
  554.  
  555. #pragma segment File
  556.  
  557. pascal short SaveScriptHook(short item, DialogPtr dlg, void * params)
  558. {
  559.     short                kind;
  560.     ControlHandle    type;
  561.     Rect                r;
  562.     DPtr                doc = (DPtr) params;
  563.     
  564.     if (GetWRefCon(dlg) != 'stdf')
  565.         return item;
  566.         
  567.     switch (item) {
  568.     case sfHookFirstCall:
  569.         GetDItem(dlg, ssd_Type, &kind, (Handle *) &type, &r);
  570.         SetCtlValue(type, doc->type);
  571.         
  572.         return sfHookFirstCall;
  573.     case ssd_Type:
  574.         GetDItem(dlg, item, &kind, (Handle *) &type, &r);
  575.         
  576.         doc->type = (DocType) GetCtlValue(type);
  577.         
  578.         return sfHookNullEvent;
  579.     default:
  580.         return item;
  581.     }
  582. }
  583.  
  584. /*
  585.     Fills in the document record with the user chosen destination
  586. */
  587.  
  588. pascal OSErr GetFileNameToSaveAs(DPtr theDocument)
  589. {
  590. #ifndef RUNTIME
  591.     OSErr                    err;
  592.     StandardFileReply    reply;
  593.     Str255            suggestName;
  594.     Point                    where;
  595.     
  596.     where.h = where.v = -1;
  597.  
  598.     GetWTitle(theDocument->theWindow, suggestName);
  599.  
  600.     CustomPutFile(
  601.         "\pSave Document As:", suggestName, &reply,
  602.         SaveScriptDialog,
  603.         where,
  604.         SaveScriptHook,
  605.         (ModalFilterYDProcPtr) nil,
  606.         nil,
  607.         (ActivateYDProcPtr) nil,
  608.         theDocument);
  609.  
  610.     if (reply.sfGood)
  611.         switch (err = FSpDelete(&reply.sfFile)) {
  612.         case noErr:
  613.         case fnfErr:
  614.             theDocument->theFSSpec = reply.sfFile;
  615.             PLstrcpy(theDocument->theFileName, reply.sfFile.name);
  616.  
  617.             return noErr;
  618.         default:
  619.             return err;
  620.         }
  621.     else
  622.         return userCanceledErr;
  623. #else
  624.     OSErr        err;
  625.     SFReply    reply;
  626.     Str255   suggestName;
  627.     Point        where;
  628.  
  629.     where.h = where.v = 75;
  630.     
  631.     GetWTitle(theDocument->theWindow, suggestName);
  632.  
  633.     SFPutFile(
  634.         where, "\pSave Document As:", 
  635.         suggestName, (DlgHookProcPtr) nil,
  636.         &reply);
  637.     
  638.     if (reply.good) {
  639.         FSSpec    spec;
  640.         
  641.         if (err = WD2FSSpec(reply.vRefNum, reply.fName, &spec))
  642.             return err;
  643.         switch (err = HDelete(spec.vRefNum, spec.parID, spec.name)) {
  644.         case noErr:
  645.         case fnfErr:
  646.             theDocument->theFSSpec = spec;
  647.             PLstrcpy(theDocument->theFileName, spec.name);
  648.  
  649.             return noErr;
  650.         default:
  651.             return err;
  652.         }
  653.     } else
  654.         return userCanceledErr;
  655. #endif
  656. } /* GetFileNameToSaveAs */
  657.  
  658. #pragma segment File
  659.  
  660. pascal OSErr OpenOld(FSSpec aFSSpec, DocType type)
  661. {
  662.     DPtr          theDocument;
  663.     OSErr         fileErr;
  664.     
  665.     theDocument = NewDocument(true, kDocumentWindow);
  666.  
  667.     SetWTitle(theDocument->theWindow, aFSSpec.name);
  668.  
  669.     SetPort(theDocument->theWindow);
  670.  
  671.     theDocument->theFSSpec   = aFSSpec;
  672.  
  673.     PLstrcpy(theDocument->theFileName,aFSSpec.name);
  674.  
  675.     theDocument->dirty               = false;
  676. #ifndef RUNTIME
  677.     theDocument->type                    = (type == kOldRuntime6Doc) ? kRuntime6Doc : type;
  678.     theDocument->u.reg.everSaved    = (type != kOldRuntime6Doc);
  679. #else
  680.     theDocument->type                    = kPlainTextDoc;
  681.     theDocument->u.reg.everSaved    = (type == kPlainTextDoc);
  682. #endif
  683.  
  684.     fileErr = GetFileContents(aFSSpec, theDocument);
  685.  
  686.     if (!fileErr) {
  687.         ResizeWindow(theDocument);
  688.         DoShowWindow(theDocument->theWindow);
  689.     } else {
  690.         if (fileErr == elvisErr) {
  691.             theDocument->u.reg.everSaved    = false;
  692. #ifdef RUNTIME
  693.             if (AEInteractWithUser(kAEDefaultTimeout, nil, nil))
  694. #endif
  695.                 if (Alert(ElvisAlert, nil) == 1)
  696.                     SaveAskingName(theDocument, true);
  697.         } else
  698.             FileError("\pError Opening ", aFSSpec.name);
  699.         
  700.         CloseMyWindow(theDocument->theWindow);
  701.     }
  702.  
  703.     return fileErr;
  704. } /* OpenOld */
  705.  
  706. pascal DocType GetDocType(FSSpec * spec)
  707. {
  708.     CInfoPBRec    info;
  709.     DocType        type    =    kUnknownDoc;
  710.     short            resFile;
  711.     short            nuFile;
  712.     OSType    **    rtType;
  713.  
  714.     if (FSpCatInfo(spec, &info))
  715.         return kUnknownDoc;
  716.     
  717.     switch (info.hFileInfo.ioFlFndrInfo.fdType) {
  718.     case 'APPL':
  719.         switch (info.hFileInfo.ioFlFndrInfo.fdCreator) {
  720.         case MPRtSig:
  721.             resFile    =    CurResFile();
  722.             nuFile    =    HOpenResFile(spec->vRefNum, spec->parID, spec->name, fsRdPerm);
  723.             
  724.             if (nuFile != -1) {
  725.                 if (rtType = (OSType **) Get1Resource('MrPL', 128))
  726.                     switch (**rtType) {
  727.                     case 'SCPT':
  728.                         type        =    kScriptDoc;
  729.                         break;
  730.                     case 'MrP7':
  731.                         type        =    kRuntime7Doc;
  732.                         break;
  733.                     case 'MrP6':
  734.                         type         =    kRuntime6Doc;
  735.                         break;
  736.                     }
  737.                     
  738.                 CloseResFile(nuFile);
  739.             }
  740.             UseResFile(resFile);
  741.             
  742.             return type;
  743.         case MPAppSig:
  744.             /* A heuristic to separate old runtimes from PowerPC executables */
  745.             if (info.hFileInfo.ioFlLgLen && info.hFileInfo.ioFlLgLen < 100000)
  746.                 return kOldRuntime6Doc; 
  747.             /* Fall through */
  748.         default:
  749.             return kUnknownDoc;
  750.         }
  751.     case 'TEXT':
  752.         return kPlainTextDoc;
  753.     case 'pref':
  754.         switch (info.hFileInfo.ioFlFndrInfo.fdCreator) {
  755.         case MPAppSig:
  756.         case MPRtSig:
  757.             return kPreferenceDoc;
  758.         }
  759.         /* Fall through */
  760.     default:
  761.         return kUnknownDoc;
  762.     }
  763. }